import type { EChartsOption, SeriesOption } from 'echarts'

import type { Ref } from 'vue'
import type { Position, PositionType } from '../types'

import type { CloudCharts } from '@/components/cloud-charts/index'

import type { UnwrapArray } from '@/types'
import { graphic } from 'echarts'
import { colors } from '../config'
import { getLegendPos, hexColorToRgb } from '../utils'
// 折线主题
export interface LineTheme {
  color: string
  areaColor: EChartsOption['color']
}

export interface TimeValue {
  timestamp: string
  value: number
}

export interface DataSource {
  label?: string
  data: Ref<TimeValue[]> | TimeValue[]
  valueFormatter?: (value: any, params?: any) => string
  theme?: LineTheme
}

// hook配置
export interface HookOptions {
  categories: Ref<string[]> | string[]
  dataSource: DataSource[] | Ref<DataSource[]>
  colors?: string[]
  legendPosition?: PositionType
  gridTop?: number
  showLegend?: boolean
  minInterval?: number
  min?: number
  max?: number
  xAxis?: {
    excludeRepeatLabel?: boolean | Ref<boolean>
  }
  // animation?: boolean
  valueFormatter?: (value: any, params?: any) => string
  YAxisFormatter?: (value: any, params?: any) => string
  labelFormatter?: (value: any, params?: any) => string
  axisLabelFormatter?: (value: any, params?: any) => string
  dataZoomLabelFormatter?: (value: any, params?: any) => string
}

// 坐标轴文字颜色
const axisLabelColor = '#A6ADB8'
// 边框颜色
const axisBorderColor = '#DFE2E5'
// 折线线宽
const lineWidth = 2

// 根据rgb颜色生成区域渐变
function getLinearGradient(r: number, g: number, b: number) {
  return new graphic.LinearGradient(0, 1, 0, 0, [
    { offset: 0, color: `rgba(${r}, ${g}, ${b}, 0.00)` },
    { offset: 1, color: `rgba(${r}, ${g}, ${b}, 0.04)` },
  ])
}

function generateLineTheme(colors: string[]) {
  return colors.map((color) => {
    const rgb = hexColorToRgb(color)
    return {
      color,
      areaColor: getLinearGradient(rgb.r, rgb.g, rgb.b),
    }
  })
}

export default function useLineCharts(options: HookOptions) {
  if (!options.dataSource) {
    throw new Error('缺少数据源配置')
  }
  options.legendPosition = options.legendPosition || 'tl'
  options.showLegend
    = options.showLegend !== undefined ? options.showLegend : true

  const selectedLegends = ref<string[]>([])
  const chartRef = ref<InstanceType<typeof CloudCharts>>()
  onMounted(() => {
    nextTick(() => {
      if (!chartRef.value) {
        return
      }
      const instance = chartRef.value?.getInstance()
      instance?.on('legendselectchanged', (e: any) => {
        const keys = Object.keys(e.selected)
        selectedLegends.value = keys.filter((key) => {
          return e.selected[key]
        })
      })
      /**
       * 下面单独指定yAxis Label的formatter。无法再options配置里的formatter动态判断selectedLegends的取值；
       * options里的formatter的执行快于echarts的事件触发，会导致取值不准，所以这儿重新指定了格式化处理函数，并重新setOptions；
       */
      const opt = instance.getOption()
      if (Array.isArray(opt.yAxis) && opt.yAxis.length) {
        opt.yAxis[0].axisLabel.formatter = (val: string) => {
          if (options.valueFormatter) {
            return options.valueFormatter(val, selectedLegends.value)
          }
          return val
        }
      }
      instance.setOption(opt)
    })
  })

  const themes = generateLineTheme(
    options.colors?.length ? options.colors : colors,
  )
  // 通过索引获取预设主题，获取不到则使用第一个
  function getTheme(index: number) {
    const _index = index % themes.length
    return themes[_index]
  }

  // 生成系列数据
  function generateSeries(dataSource: DataSource[] | Ref<DataSource[]>) {
    return unref(dataSource).map((item, index) => {
      const _t = getTheme(index)
      return {
        type: 'line',
        name: item.label,
        smooth: true,
        // zIndex: index, // 图例顺序
        // large: true, // 大数据量优化
        // largeThreshold: 400, // 大数据量优化
        // progressive: 500,
        // progressiveThreshold: 1000,
        showSymbol: false,
        color: item.theme?.color || _t.color,
        lineStyle: {
          width: lineWidth,
        },
        areaStyle: {
          color: item.theme?.areaColor || _t.areaColor,
        },
        emphasis: {
          focus: 'series',
        },
        data: unref(item.data),
      } as SeriesOption
    })
  }

  // 获取grid位置，需要根据legend位置动态计算
  function getGridPos() {
    const gap = 10
    const pos: Position = { left: 0, top: 0, right: 20, bottom: 0 }
    if (options.legendPosition?.startsWith('t')) {
      pos.top
        = options.showLegend || options.gridTop ? options.gridTop || 52 : gap
      pos.bottom = gap
    }
    if (options.legendPosition?.startsWith('b')) {
      pos.top = gap
      pos.bottom = options.showLegend ? 44 : gap
    }
    return pos
  }

  // 生成图例数据
  function generateLegendData(): NonNullable<
    UnwrapArray<EChartsOption['legend']>
  >['data'] {
    return unref(options.dataSource).map((item, index) => {
      const _t = getTheme(index)
      return {
        name: item.label,

        textStyle: {
          color: _t.color,
        },
      }
    })
  }

  function getSeriesValueFormatter(seriesName: string, sources: DataSource[]) {
    return sources.find(item => item.label === seriesName)?.valueFormatter
  }

  // 折线图表配置
  const chartsOptions = computed(() => {
    const xAxisLabels: Set<string> = new Set()
    let xAxisLabelInterval:
      | string
      | ((index: number, value: string) => boolean) = 'auto'

    if (unref(options.xAxis?.excludeRepeatLabel)) {
      xAxisLabelInterval = (_index: number, value: string) => {
        const formatter = options.axisLabelFormatter || options.labelFormatter
        const label = formatter ? formatter(value) : value
        if (xAxisLabels.has(label)) {
          xAxisLabels.add(label)
          return false
        }
        xAxisLabels.add(label)
        return true
      }
    }

    return {
      grid: {
        ...getGridPos(),
        top: '64',
        left: '24',
        right: '64',
        bottom: '64',
        containLabel: true,
      },
      legend: {
        show: options.showLegend,
        type: 'scroll',
        itemGap: 16,
        itemWidth: 20,
        itemHeight: 8,
        data: generateLegendData(),
        ...getLegendPos(options.legendPosition!),
      },
      tooltip: {
        trigger: 'axis',
        formatter: (arr: any[]) => {
          if (!arr) {
            return ''
          }
          arr.sort((a, b) => {
            return b.value - a.value
          })
          const xLabelValue = arr[0].axisValueLabel
          return `
            <div class="line-tooltip">
              <div class="time">${formatUnix(xLabelValue, 'YYYY-MM-DD HH:mm:ss')}</div>
              <div class="series">
                ${arr
                  .map((item) => {
                    const formatter
                      = getSeriesValueFormatter(
                        item.seriesName,
                        unref(options.dataSource),
                      ) || options.valueFormatter
                    return `
                    <div class="series-item">
                      <div style="border-color: ${item.color}"></div>
                      <div>${item.seriesName}</div>
                      <div>
                        ${formatter && formatter(item.value, item.seriesName)}
                      </div>
                    </div>
                  `
                  })
                  .join('')}
              </div>
            </div>
          `
        },
      },
      dataZoom: [
        {
          show: true,
          realtime: false,
          start: 0,
          end: 100,
          xAxisIndex: [0, 1],
          labelFormatter(_, val?: any) {
            const formatter
              = options.dataZoomLabelFormatter || options.labelFormatter
            if (formatter) {
              return formatter(val)
            }
            return val
          },
          // textStyle: {
          //   color: 'rgba(0, 0, 0, 0)'
          // }
        },
      ],
      xAxis: {
        type: 'category',
        data: unref(options.categories),
        boundaryGap: false,
        axisLabel: {
          color: axisLabelColor,
          margin: 16,
          formatter: (val) => {
            const formatter
              = options.axisLabelFormatter || options.labelFormatter
            if (formatter) {
              return formatter(val)
            }
            return val
          },
          interval: xAxisLabelInterval,
        },
        axisTick: { show: false },
        axisLine: {
          lineStyle: {
            type: 'solid',
            color: axisBorderColor,
          },
        },
      },
      yAxis: {
        type: 'value',
        minInterval: options.minInterval,
        min: options.min,
        max: options.max,
        axisLabel: {
          color: axisLabelColor,
          margin: 16,
          formatter: options.YAxisFormatter
            ? options.YAxisFormatter
            : options.valueFormatter,
        },
        splitLine: {
          lineStyle: {
            type: 'dashed',
            color: axisBorderColor,
          },
        },
      },
      // animation: options.animation, // 关闭动画
      // animationDuration: 100,
      series: generateSeries(options.dataSource),
    } as EChartsOption
  })

  return {
    options: chartsOptions,
    chartRef,
    selectedLegends,
  }
}
